# token在这里
# 用户注册和用户登录的地方
from flask_restful import Resource, reqparse, abort, fields, marshal

from App.apis.api_constant import HTTP_CREATE_OK, USER_ACTION_LOGIN, USER_ACTION_REGISTER, HTTP_OK
from App.apis.cinema_admin.cinema_utils import get_cinema_user
from App.ext import cache
from App.models.cinema_admin.cinema_user_model import CinemaUser
from App.token_utils import generate_cinema_user_token


# parse用途：过滤数据
# 由于注册和登录的限制程度不同，所以分为以下几种parse，因为登录的时候用户名和手机号可以不必要同时填写，因此做了一个过滤分流

parse_base = reqparse.RequestParser()           # 这个是基础限制
parse_base.add_argument('password', type = str, required=True, help ='请输入密码')
parse_base.add_argument("action", type = str, required=True, help ="请确认请求参数（登录还是注册）")

parse_register = parse_base.copy()      # 继承了parse_base。这个是注册的时候要求的，必须都要填
parse_register.add_argument('phone', type = str, required=True, help ='请输入手机号')
parse_register.add_argument('username', type = str, required=True, help ='请输入用户名')

parse_login = parse_base.copy()      # 继承了parse_base。这个是登录的时候要求的，此时用户名和手机号不是必须填写的了
parse_login.add_argument('phone', type = str , help ='请输入手机号')
parse_login.add_argument('username', type = str , help ='请输入用户名')

# fields用途：格式化数据
cinema_user_fields = {
    "username":fields.String,
    "password":fields.String(attribute = "_password"),
    "phone":fields.String,
    "is_verify":fields.Boolean
}

single_cinema_user_fields = {
    "status": fields.Integer,
    "msg":fields.String,
    "data":fields.Nested(cinema_user_fields)
}

# 客户端的用户，不应有访问所有用户的get读取权限
class CinemaUsersResource(Resource):

    # marshl_with
    def post(self):
        args = parse_base.parse_args()      #这个args是base过滤里面的
        password = args.get('password')
        # username = args.get('username')     #这一句要挪到注册分支里面，因为这里用的是base的过滤，里面没有申明username这一个字段，用args的话get不到
        action = args.get("action").lower()

        if action == USER_ACTION_REGISTER:          # 注册分支
            args_register = parse_register.parse_args()     #这个args_register是注册过滤里面的
            phone = args_register.get('phone')
            # password = args_register.get('password')      # password属于base字段，直接放在分支的外面就行
            username = args_register.get('username')        #？不加的话就拿不到username，为什么要加这个，44行不是已经拿到了吗? 答：因为用的过滤不同

            cinema_user = CinemaUser(username = username , password = password , phone = phone)
            if not cinema_user.save():
                abort(400 , msg = '注册用户失败')
            data = {
                "status": HTTP_CREATE_OK,
                "msg": "注册用户成功",
                "data":cinema_user       #一个对象本来不可序列化，但是用了marshal就可以了
            }
            return marshal(data, single_cinema_user_fields)

        elif action == USER_ACTION_LOGIN:           # 登录分支
            args_login = parse_login.parse_args()   #这里用的是login的过滤
            username = args_login.get('username')
            phone = args_login.get('phone')
            # password = args_login.get('password')     # password属于base字段，直接放在分支的外面就行
            user = get_cinema_user(username) or get_cinema_user(phone)        # 在数据库里找，找得到就返回，找不到就返回none
            if not user:
                abort(400 , msg = "用户不存在")

            if not user.check_password(password):       # 检验密码是否错误
                abort(401 , msg = "密码错误")

            if user.is_delete:
                abort(401 , msg = "用户不存在")

            # token = uuid.uuid4().hex            # 走到这一步就证明用户密码都对得上了，就生成一个token，为后续操作准备
            # # 但是这种token生成的方式不完善，，存缓存时候键值对容易跟其他的表id撞了。可以采用对token加前缀的形式。像下面这样

            token = generate_cinema_user_token()     # 封装一个方法，使token是带cinema_user前缀的，用来区分不同token
            cache.set(token , user.id , timeout = 60*60*24*7)       # 根据用户名去给它绑定一个token，放到缓存里面.token相当于键，id相当于值

            data = {
                "msg" : "login success",
                "status":HTTP_OK,
                "token": token
            }
            return data

        else:
            abort(400 , msg = "请提供正确的参数（登录还是注册）")



